
<head>
<script>
  (function (w,d,s,o,f,js,fjs) {
  w[o] = w[o] || function () { (w[o].q = w[o].q || []).push(arguments) };
  js = d.createElement(s), fjs = d.getElementsByTagName(s)[0];
  js.id = o; js.src = f; js.async = 1; fjs.parentNode.insertBefore(js, fjs);
  }(window, document, 'script', 'plausible', 'https://plausible.io/js/p.js'));

  plausible('page')
</script>
</head>
<html>
<body>
<table cellpadding=10><tr valign=top><td>
  <table>
  <tr><td>Test Feedrate<td><input id=ifeed size=4 value=120>
  <tr><td>Max Accel<td><input id=iacc size=4 value=500>
  <tr><td>Jerk<td><input id=ijerk size=4 value=8000>
  <tr><td>Corner<td><input id=icorner size=4 value=30>
  <tr><td colspan=2>GRAPHICS
  <tr><td>X SCALE<td><input id=igsx size=4 value=150>
  <tr><td>Y SCALE<td><input id=igs size=4 value=3>
  <tr><td>Demo<td><select id=idemo>
	<option value="line" selected>Line</option>
	<option value="box">Box</option>
	<option value="circle" >Circle</option>
	</select>
  <tr><td colspan=2><button onclick="dodemo()">Run demo</button>
  
  </table>	
<td>  
  <canvas style="background:black" id=drw width="900" height="500"></canvas>
</table>
  <script>

function $(id) {
  return document.getElementById(id);
}

function mround(x) {
	return Math.round(x * 100.0) / 100.0;
}

function getvalue(el) {
	if ($(el)==undefined)return "";
	if (el=="gcode")return editorgcode.getValue();
    else return $(el).value;
}

var micros=Date.now;
var c = document.getElementById("drw");
var ctx = c.getContext("2d");
zprintf=console.log;
function PSTR(x){return x;}
var float=parseFloat;
function fmax(a,b){return (a>=b)?a:b;}
function fmin(a,b){return (a>=b)?b:a;}
function InvSqrt(f) {return 1.0/Math.sqrt(f);}

function xInvSqrt(n) {return stepdiv2*(n>0.0625?InvSqrt(n):4);}
function zInvSqrt(n) {return stepdiv2/n;}
//function xInvSqrt(n) {return Math.round(Math.sqrt(n));}
function sqr(n) {return n*n;}
var vv=[];
var ddd=[];
var CLOCKCONSTANT=80000000;
var STEPFREQ=50000;
var STEPCLOCK=Math.round(CLOCKCONSTANT/STEPFREQ);
var rampv=1;
var minVel=1;
var head=0;
var tail=0;
var NUMBUFFER=100;
var move=[];
var moves=[];
var isG0;
var m,nm;
var f=0;
var x1=0;
var y1=0;
var z1=0;
var e1=0;

var maxf=[100,100,100,100,0];
maxf[4]=max(maxf[0],max(max(maxf[1],maxf[2]),maxf[3]));
var stepmm=27.5;
var accel=40;
var jerk=5*accel;
var zaccel=accel;
var mvaccel=accel;
var xycorner=35;
var zcorner=xycorner;
var labs=Math.abs;
var fabs=Math.abs;

var laxis;
var fastaxis;
var totalstep;
var oacup,acup;
var oacdn,acdn;
var ta;
var stepdiv,stepdiv2;
var nextmicros;
var mctr2;
var nextdly;
var ldelay=0;

var dlp=0;
var cmd0=0;
var cmddelay=[0];
var cmdhead=0;
var cmdtail=0;
var lastmm=[0,0,0,0,0];
var currmm=[0,0,0,0,0];
var mmdis=[0,0,0,0,0];
var mcx=[0,0,0,0];
var bsdx=[0,0,0,0];
var sx=[0,0,0,0];

/// command buffer
var NUMCMDBUF=100000;
function prevbuffm(x) {return ((x) > 0 ? (x) - 1 : NUMCMDBUF-1);}
function nextbuffm(x) {return ((x) < NUMCMDBUF-1 ? (x) + 1 : 0);}
for (var i=0;i<NUMBUFFER;i++){move.push({});}
//for (var i=0;i<NUMCMDBUF;i++){cmddelay.push(0);}

var cmhead = 0;
var cmtail = 0;
var cmcmd;
var cmbit = 0;
var cmdlaserval = 0;

var mo = 0;
function cmdfull() {return nextbuffm(cmhead)==cmtail;}
function cmdnotfull() {return nextbuffm(cmhead)!=cmtail;}
function cmdempty () {return cmhead==cmtail;}

var nextok = 0;
var laserwason = 0;

var sendwait = 0;

var maincmdlaserval = 0;

function pushcmd()
{


  // if move cmd, and no motor move, save the delay
//  if ( (cmd0 & 1) && !(cmd0 & (15 << 1))) {
//    ldelay += cmd0 >> 5;
//  } else {
  if ( (cmd0 & 1)) {
    ldelay += cmd0 >> 5;
    cmhead = nextbuffm(cmhead);
    if (cmd0 & 1)cmd0 += (ldelay << 5);
    //cmddelay[cmhead] = cmd0;
    cmddelay.push(cmd0);
    ldelay = 0;
  }

}

function pullcmd()
{
	cmhead = prevbuffm(cmhead);
}

function newdircommand(laserval)
{
  // change dir command
  //cmd0 = 0;//DIRDELAY << 6;
  cmd0 = (laserval << 9);
  if (sx[0] > 0)cmd0 |= 2;
  if (sx[1] > 0)cmd0 |= 8;
  if (sx[2] > 0)cmd0 |= 32;
  if (sx[3] > 0)cmd0 |= 128;
  // TO know whether axis is moving
  if (bsdx[0] > 0)cmd0 |= 4;
  if (bsdx[1] > 0)cmd0 |= 16;
  if (bsdx[2] > 0)cmd0 |= 64;
  if (bsdx[3] > 0)cmd0 |= 256;
  ldelay = 0;
  pushcmd();

}



function bufflen() {return  head >= tail ? head - tail : (NUMBUFFER + head) - tail;} // 5+0 - 4

function nextbuff(x) {return (x) < NUMBUFFER-1 ? (x) + 1 : 0;}
function prevbuff(x) {return ((x) > 0 ? (x) - 1 : NUMBUFFER-1);}
function copy(a,b){
  for (var i=0;i<b.length;i++){
    a[i]=b[i];
  }
}

function int(x){return Math.floor(x);}
function max(a,b){return (a>=b)?a:b;}
function min(a,b){return (a<=b)?a:b;}
function abs(a){return Math.abs(a);}
var sqrt=Math.sqrt;
function sqr2(x){return x*x;}




var MINCORNERSPEED=0.3;
var lastf=0;
var curru=[0,0,0,0,0];
var prevu=[0,0,0,0,0];
var tailok=0;


function FASTAXIS(m){
	return (m.status >> 4)&3;
}

// float

var scurve=0;

var has1,has2,has3,has4,has5,has6,has7;
var s1,s2,s3,s4,s5,s6,s7;
var vjerk1,vjerk7,vi,vc,ve;
var a1x,a1,a2,as3,as7,ja,T,V,S,Sdest,tstep,tstepS;
// int
var sg,ok;
var prevacc=0;
var nextacc=0;
var curracc=0;

function ramplenq(v0,v1,stepa) {
	return (v1-v0)*stepa;
}	

function ramplenq2(v0,v1,stepa) {
	return 0.5*tosteps*(v1-v0)*stepa;
}	

function speedat(v0,a,s) {return (a * s  + v0);}

var rampup,rampdown,tosteps;
var stepa,acdn,acup;
function prepareramp(bpos)
{
	// local m
	scurve=jerk>0;
    var m = move[bpos];
	faxis = FASTAXIS(m);
	ytotalstep = labs(m.dx[faxis]);
	// trapezoid ramps up /down
	var ru, rd;
	ru = rd = 0;
	accel2=2*accel;
	stepa = 1.0 / (accel2);

	ru=ramplenq(m.fs, m.fn, stepa);
	rd=ramplenq(m.fe, m.fn, stepa);



	if (ru + rd > m.dis) {
		// if crossing and have rampup
		var r = ((ru + rd) - m.dis) / 2;
		ru -= r;
		rd -= r;
		if (ru < 0)ru = 0;
		if (rd < 0)rd = 0;
		if (rd > m.dis)rd = m.dis;
		if (ru > m.dis)ru = m.dis;
		m.fn = speedat(m.fs, accel2, ru);

		//    if (rd== 0)next->fs = m.fn;
	}

	// convert to steps
	tosteps=ytotalstep / m.dis;
	ru = Math.floor(ru * tosteps);
	rd = Math.floor(rd * tosteps);

	//if (m.fs-m.fe>=m.delta) m.fn=m.fs;
	prevacc=curracc;
    if (bpos!=(head)) {
        next=move[nextbuff(bpos)];
		//if (next.fs-next.fe>=next.delta) next.fn=next.fs;

        if (next.fs==next.fn && next.fe<next.fn) {   // all down
			nextacc=-1;
		} else
        if (next.fe==next.fn && next.fs<next.fn) {   // all up
			nextacc=1;
        } else
		if ((next.fe==next.fn) && (next.fs==next.fn)) {   // all up
			nextacc=0;
		} else {
			nextacc=1; 
		}
    } else {
		//fe=0;
		nextacc=0;
	}

	has4=m.delta>Math.abs(m.fe-m.fs);

	if (m.fs==m.fn && m.fe<m.fn) {   // all down
		curracc=-1;
	} else
	if (m.fe==m.fn && m.fs<m.fn && !has4) {   // all up
		curracc=1;
	} else
	if (m.fe==m.fn && m.fs==m.fn) {   // all up
		curracc=0;
	} else {
		if (m.fn>m.fe) curracc=-1; else curracc=0; 
	}

	
    // identify which segment is available
	// 
	// lets check 1 by 1 
	//
	mvjerk = scurve?(0.5*accel*accel/jerk):0;

	vjerk1=0;
	// if 
	// segment 1, prevacc <=0 and fs<fn
	has1=scurve && (prevacc<=0) && (m.fs<m.fn);
	// segment 3, curracc <=0 and fs<fn
	has3=scurve && (has4) && (m.fs<m.fn);

	if (has1)vjerk1+=mvjerk;
	if (has3)vjerk1+=mvjerk;
	// segment 2, constant acceleration prevacc <=0 and fs<fn
	//has2=(m.fn-m.fs>vjerk1*vjerk1);	
	
	vjerk7=0;
	//
	// segment 1, prevacc <=0 and fs<fn
	has7=scurve && (nextacc>=0) && (m.fe<m.fn);
	// segment 3, curracc <=0 and fs<fn
	has5=scurve && (curracc<=0 && has4) && (m.fe<m.fn);
	if (!has4 && prevacc==-1 && curracc==-1)has5=0;

	

	if (has7)vjerk7+=mvjerk;
	if (has5)vjerk7+=mvjerk;
	// segment 2, constant acceleration prevacc <=0 and fs<fn
	has6=(m.fn-m.fe>vjerk7*vjerk7);	
	
	
	
	vi=m.fs;
	vc=m.fn;
	ve=m.fe;
	vi1=sqrt(m.fs);
	vc1=sqrt(m.fn);
	ve1=sqrt(m.fe);
	
	//preparejerk(m.dis);
	var delta1, delta7, saccelerate;
	var jerk6 = 0.16667 * jerk;
	
	if (has1 || has3){
		vjerk1=min(vjerk1,Math.abs(vc1-vi1));
		if (has1 && has3)vjerk1=vjerk1*0.5;
		t1 = sqrt(2.0 * vjerk1 / jerk); // calc time to reac vjerk segment 1
		delta1 = jerk6 * t1 * t1 * t1;
	} else t1=0;
	
	if (has1){
		s1 = Math.floor((vi1 * t1 + delta1)*tosteps);
		//s1=Math.ceil(ramplenq2(vi,vi+vjerk1,stepa));
	} else {
		s1=0;
	}
	if (has3){
		//s3=Math.ceil(ramplenq2(vc-vjerk1,vc,stepa));
		s3 = Math.floor((vc1 * t1 - delta1)*tosteps);
	} else {
		s3=0;
	}
	s2=ru-s1-s3;
	has2=s2>0;
	if (has2){
		//has2=1;
	} else {
		if (s2<0){
			sc=ru/(s1+s3);
			s1=Math.floor(s1*sc);
			s3=Math.floor(s3*sc);
		}
		s2=0;
		
	}
	// calc new rate for up
	accel2=accel2/tosteps;
	
	if (ru){
		acup=accel2*(ru/(ru-0.5*(s1+s3)));
	} else acup=accel2;
	// ===============================
	if (has5 || has7){
		vjerk7 = fmin(vjerk7, fabs(vc1 - ve1));
		if (has5 && has7)vjerk7 = vjerk7 * 0.5;
		t7 = sqrt(2.0 * vjerk7 / jerk); // calc time to reac vjerk segment 1
		delta7 = jerk6 * t7 * t7 * t7;
	}
	
	if (has7){
		//s7=Math.ceil(ramplenq2(ve,ve+vjerk7*vjerk7,stepa));
		s7 = Math.floor((ve1 * t1 + delta7)*tosteps);
	} else {
		s7=0;
	}
	if (has5){
		//s5=Math.ceil(ramplenq2(vc-vjerk7*vjerk7,vc,stepa));
		s5 = Math.floor((vc1 * t7 - delta7)*tosteps);

	} else {
		s5=0;
	}
	s6=rd-s5-s7;
	has6=s6>0;
	if (has6){
		//has2=1;
	} else {
		if (s6<0){
			sc=rd/(s5+s7);
			s5=Math.floor(s5*sc);
			s7=Math.floor(s7*sc);
		}
		s6=0;
		
	}
	// calc new rate for down
	if (rd){
		acdn=accel2*(rd/(rd-0.5*(s5+s7)));
	} else acdn=accel2;
	
	s4=ytotalstep-rd-ru;
	has4=s4>0;
	if (has4){
	} else s4=0;
	
	has1=s1>0;
	has3=s3>0;
	has5=s5>0;
	has7=s7>0;
	


	sg=0;
	ok=0;
	S=0;
	Sdest=0;
	V=vi;
	
    m.status |= 4;
}

function deltaV2(s){
    return 2*accel*s;
}

function backforward()
{
// now back planner
    h=head;//
    //h=prevbuff(head);
    if (h==tailok) {
        return 0;
    }

    var next;
    var curr = 0;
    while (1) {
        next=curr;
		fs=next?next.fs:MINCORNERSPEED;
        curr=move[h];
		curr.fe=fs;
        if (curr.fs!=curr.maxs) {
			curr.fs=min(fs+curr.delta,curr.maxs); // maximum speed from next start 
        }
        h=prevbuff(h);
		if (h==tailok)break;
    }

// forward
    h=tailok;
	
	next=move[h];
    h=nextbuff(h);
    while (h!=head) {
        curr=next;
        next=move[h];
		curr.fe=next.fs;
        if (curr.fs<next.fs) { // if this start speed is less then next start /
            fs=curr.fs+curr.delta; // maximum speed at end
            if (fs<next.fs) { // if next start is less than this maximum speed , then its final
                next.fs=fs;
				curr.fe=fs;
				//curr.fn=fs;
                tailok=prevbuff(h);
            }
            curr.fn=max(curr.fe,min(fs,curr.fn));
        }
        if (next.fs==next.maxs) tailok=prevbuff(h);
        h=nextbuff(h);
    }

}


function planner(h){
  curr=move[h];
  scale=1;
  xtotalstep=abs(curr.dx[curr.faxis]);
  copy(prevu,curru);
  curru[4] = 1;
//  m.accel=accel;
  for (var i=0;i<4;i++){
    curru[i]=0;
    if (curr.dx[i]!=0){
      cdx = (curr.fn) * mmdis[i];
      if ((i != 3)) {
        scale2 = (maxf[i]) * curr.dis / fabs(cdx);
        if (scale2 < scale) scale = scale2;
      }
      // if Z then need to scale the acceleration too
      if (i == 2) {
        //scalea = zaccel * curr.dis / fabs(accel * mmdis[i]);
        //if (scalea < 1)m.accel *= scalea;
      }
      curru[i] = mmdis[i] / curr.dis;
    }
  }
  var ucorner = xycorner;//* scale;
  curr.fn*=scale;
  curr.fn*=curr.fn;

  max_f = MINCORNERSPEED;
  if (bufflen()>1) {

     var junc_cos = -prevu[0] * curru[0] - prevu[1] * curru[1] - prevu[2] * curru[2];
    if (junc_cos > 0.999999) {
      max_f = MINCORNERSPEED;
    } else if (junc_cos < -0.999999) {
      max_f = 400;
    } else {
      var sin_theta_d2 = sqrt(0.5 * (1.0 - junc_cos)); // Trig half angle identity. Always positive.
      max_f = fmax( MINCORNERSPEED, (ucorner * ucorner* sin_theta_d2 / (1.0 - sin_theta_d2) ));
    }


  }
  curr.maxs=min(curr.fn,lastf);
  curr.maxs=min(curr.maxs,max_f);
  lastf=curr.fn;
  backforward();
}

var lastx=0;
var lasty=0;

function addmove(fn,x2,y2,z2,e2,g0,rel) {
  fn=min(fn,maxf[4]);
  var curr=move[nextbuff(head)];
  if (rel) {
    x2+=x1;
    y2+=y1;
    z2+=z1;
    e2+=e1;
  }
  copy(lastmm,currmm);
  currmm[0]=mmdis[0] = (x2 - x1);
  currmm[1]=mmdis[1] = (y2 - y1);
  currmm[2]=mmdis[2] = (z2 - z1);
  mmdis[3] = (e2 - e1);

  var dx=[];
  dx[0]=int(x2*stepmm)-int(x1*stepmm);
  dx[1]=int(y2*stepmm)-int(y1*stepmm);
  dx[2]=int(z2*stepmm)-int(z1*stepmm);
  dx[3]=int(e2*stepmm)-int(e1*stepmm);

  curr.dis = sqrt(sqr2(mmdis[0]) + sqr2(mmdis[1]) + sqr2(mmdis[2]));
  curr.dx=dx;
  
  dd=0;
  faxis=0;
  for (var i=0;i<4;i++){
    var d=Math.abs(dx[i]);
	if (d>dd){
      dd=d;
      faxis=i;
    }
  }

  head=nextbuff(head);
  curr.fdis=mmdis[faxis];
  curr.fn=fn;
  curr.fs=MINCORNERSPEED;
  curr.fe=MINCORNERSPEED;
  curr.status=g0?8:0;
  curr.x1=x1;
  curr.y1=y1;
  curr.z1=z1;
  curr.faxis=faxis;
  curr.delta=deltaV2(curr.dis)-0.005;
  curr.status |= faxis << 4;
  curr.status|=1;
  planner(head);
  x1=x2;
  y1=y2;
  z1=z2;
  e1=e2;

}

var GX=[0,0,0,0];
function bresenham(ix){
  if ((mcx[ix] -= bsdx[ix]) < 0) {
    cmd0 |=2<<ix;	
    mcx[ix] += totalstep;
	GX[ix]+=sx[ix];
	
	
  }
}

var lsteps=0;
var mi=0;
function machinemove(sg,dis,vel){
}

// curveloop is iterating each timestep (i set 0.001 sec) for changing velocity from constant jerk
// by change the initial a1x,a2 we can use this function for all 7 segment
// this mean the velocity only will change each 0.001 sec
// then in this timestep it check the lastS versus currentS in motor stepper steps
// it will move the motor (currentS - lastS) steps with current velocity

function curveloop(){
	if (--Sdest==0)return 0; // continue until reach each segment distance , if reached, then need to initialize next segment
	a2+=a1x; // jerk add to acceleration
	V+=a2;   // acceleration add to velocity
	dlp=Math.floor(stepdiv2/sqrt(V)); // T = CPU_CLOCK/Vel
	// do bresenham this step longs
	mctr--;
	if (mctr){
		cmd0 = 1; //step command
		// bresenham movement on all laxis and set motor motion bit to cmd0
		bresenham(0); //
		bresenham(1);
		//bresenham(2);
		//bresenham(3);

		// push T=CLOCK/V to timer command buffer
		cmd0 |= dlp << 5; // cmd0 is 32bit data contain all motor movement and the timing
		pushcmd();
		
		// lets save the data for display too
		vv.push([sqrt(V),mi]);
	}
	return 1;
}

function coreloop1(){
  //if (!m || (mctr <= 0)) {
    //zprintf(PSTR("R\n"));
    //return 0;
  //}


  if (cmdfull()) {
    zprintf(PSTR("F\n"));
  } else   {

	if (!ok){
		sg++;
		// initialize each segment 
		if (sg==1){ // constant jerk segment
			if (has1){
				a2=0;
				a1x=acup/s1;
				Sdest=s1;
			} else sg++; // next segment
		}
		if (sg==2) {// constant acc segment
			if (has2){
				a2=acup;
				//V=vi+(has1?vjerk1:0);
				a1x=0;
				Sdest=s2;
			} else sg++;
		}
		if (sg==3) {// constant jerk deceleration segment
			if (has3){
				a2=acup;
				V=vc-acup*s3*0.5;
				a1x=-acup/s3;
				Sdest=s3;
			} else sg++;
		}
		if (sg==4) {// constant velocity segment
			if (has4){
				V=vc;
				a2=0;
				a1x=0;
				Sdest=s4;
			} else sg++;
		}
		if (sg==5) {
			if (has5){
				a2=0;
				a1x=-acdn/s5;
				//V=vc;
				Sdest=s5;
			} else sg++;
		}
		if (sg==6) {
			if (has6){
				a2=-acdn;
				a1x=0;
				//V=vc-(has5?acdn*s5*0.5:0);
				Sdest=s6;
			} else sg++;
		}
		if (sg==7) {
			if (has7){
				a1x=acdn/s7;
				a2=-acdn;
				V=ve+acdn*s7*0.5;//+a2*0.5; // needed to make sure we reach accurate exit velocity
				Sdest=s7;
			} else sg++;
		}
		if (sg==8) return 0; // if happen, need to start new move
		
	}
	ok=curveloop();

  }
  return 1;
}



function startmove()
{

    if ((head == tail)) {
        return 0;
    }
    t = nextbuff(tail);
	m=move[t];
	laxis = fastaxis;
	fastaxis = FASTAXIS(m);
	totalstep = labs(m.dx[fastaxis]); // totalstep needed in bresenham

    prepareramp(t);
	if (m.dis==0)return 0;
	// global m
	isG0 = m.status & 8;



	
	stepdiv = Math.floor(CLOCKCONSTANT* m.dis / totalstep);
	stepdiv2 = wstepdiv2 = stepdiv;
	m.status &= ~3;
	m.status |= 2;


	if (f == 0)
		nextmicros = micros();// if from stop

	mctr2 = mcx[0] = mcx[1] = mcx[2] = mcx[3] = 0; //mctr >> 1;
	tail = t;


	for (var i = 0; i < 4; i++) {


	if (m.dx[i] > 0) {
	  bsdx[i] = (m.dx[i]);
	  sx[i] = 1;
	} else {
	  bsdx[i] = -(m.dx[i]);
	  sx[i] = -1;
	}
	}
	var ff=max(m.fe,max(m.fs,m.fn)); // get fastest speed
	mctr =totalstep; 
	newdircommand(!isG0 ? 255 : 0);
	// laser
	mi++;
	return 1;
}
// ===================================================================================
// MAIN CODE
// ===================================================================================

var tm=0;
var GS=12;
var GSX=100;
var GrY=c.height;
var GrX=40;
function dodemo(){
	// reset simulation
	GS=getvalue("igs")*1;
	GSX=getvalue("igsx")*1;
	
	head=0;
	tail=0;
	tailok=0;
	cmhead=0;
	cmtail=0;
	vv=[];
	GX=[0,0,0,0];
	nextacc=0;
	curracc=0;
	prevacc=0;
	cmddelay=[];
	ddd=[];
	f=0;
	x1=0;
	y1=0;
	z1=0;
	e1=0;
	mi=0;
	moves=[];
	lastf=MINCORNERSPEED;

	ctx.clearRect(0,0,1000,1000);
	demo=getvalue("idemo");
	feed=getvalue("ifeed")*1;
	accel=getvalue("iacc")*1;
	jerk=getvalue("ijerk")*1;
	zaccel=accel;
	mvaccel=accel;
	xycorner=getvalue("icorner")*1;
	zcorner=xycorner;
	
	if (demo=="box"){

		addmove(feed,100,0,0,0);
		addmove(feed,100,100,0,0);
		addmove(feed,0,100,0,0);
		addmove(feed,0,0,0,0);
	}
	if (demo=="line"){
		addmove(feed,20,10,0,0);
		addmove(feed,20,40,0,0);
	}
	if (demo=="circle"){
	  for(var x=0;x<6;x++){
		var d=x*3.14/10;
		var r=30;
		//addmove(feed, +Math.sin(d)*r, Math.cos(d)*r, 0, 0);
	  }
	for (var x = 1; x < 36; x++) {
      addmove(feed, Math.sin(x/5.70)*30, Math.cos(x/5.70)*30, 0*Math.cos(x/5.70)*30, 0*Math.sin(x/5.70)*30,0);
  }
  
	addmove(50, 0, 0, 0, 0);
	}
	ss=2.0/stepmm;
	var ox=0;oy=0;
	var xi=0;
	var colors=["red","white","blue","green"];
	//return;
	while (startmove()){
		// bresenham motion loop
		xi++;
		while (coreloop1()){
			x=350+GX[0]*ss;
			y=80+GX[1]*ss;
			if (ox>0){
				
				ctx.beginPath();
				ctx.strokeStyle=colors[xi & 3];
				ctx.moveTo(ox,oy);
				ctx.lineTo(x,y);
				ctx.stroke();
				
			}
			ox=x;
			oy=y;
		};
	}

	var cmdly,cmcmd;
	function decodecmd()
	{
	  if (cmdempty()) {

		return 0;

	  }
	  cmtail = nextbuffm(cmtail);
	  var cmd = cmddelay[cmtail];
	  cmcmd = cmd & 1;
	  if (cmcmd) {
		cmbit = (cmd >> 1) & 15;
		cmdly = (cmd >> 5);
	  } else {
		cmbit = (cmd >> 1) & 255;
		cmdly = 20;
	  }
	  return 1;
	}

		
	ff=0;
	ctx.beginPath();

	ctx.strokeStyle="#77cccc11";
	ctx.fillStyle="green";
	for (var Y=0;Y<feed/5;Y++){
		ctx.moveTo(GrX,GrY-Y*5*GS);
		ctx.lineTo(1600,GrY-Y*5*GS);
		ctx.fillText(Y*5,GrX-30,GrY-Y*5*GS);
	}
	ctx.stroke();

	function drawF(intp,c,mask,ZY){
		x=GrX;
		var ni=0;
		cmtail=0;
		var stepd=CLOCKCONSTANT/stepmm;
		var ldly=0;
		var ox=x;
		var oy=GrY-ZY;
		var oi=-1;
		while (decodecmd()){
			if (cmcmd){
				ldly+=cmdly;
				f=8*CLOCKCONSTANT/(cmdly*stepmm); // we can get from here sinve stepdiv2 is different on each path, and we dont keep the value of stepdiv2
				v=vv[ni++];
				f=v[0]*GS;
				//f=stepd*GS/getf2(ni++);
				tm+=cmdly;
				y=GrY-f+ZY;
				if (oi!=v[1]){
					ctx.stroke();
					ctx.beginPath();
					oi=v[1];
					ctx.strokeStyle=colors[oi & 3];
					ctx.moveTo(ox,oy);
				}
				if (oi>=0)ctx.lineTo(x, y);
				ox=x;
				oy=y;
				x+=cmdly*GSX/(CLOCKCONSTANT);
			}// else 	ldly+=cmdly;
		}
		ctx.stroke();
	}


	drawF(0,"green",2,0);
	//drawF(1,"red",2,0);

}
//dodemo();

</script>
</body>
</html>
